package libnetdb.dm.assoc.base;

/**
 * <p>This class defines the so called assocation rule. An association
 * rule mainly consists of two parts, i.e., the cause and the
 * consequence. Note that the elements in cause and those in the
 * consequence must be exculsive, i.e., one element cannot appear in
 * the cause set and consequence set in the same rule. For example,
 * in the rule {A,B,C} --> {D,E}, the set {A, B, C} is the cause set
 * and {D, E} is the consequence set.</p>
 *
 * <p>The ratio of the transactions contain all the elements of cause
 * set and consequence set are named support. And the ratio of
 * transactions which contain the cause set also the consequence set
 * are named confidence. This two indexes are the most referenced
 * strength measurements of an association rule.</p>
 *
 * <p>Besides the two strength measurements, in this implementation,
 * we provides another two useful indexes, one is the interesting of
 * the rule, the other is the chi-square value of the rules. Higher
 * values of these two indexes indicates more interesting the
 * rule is.</p>
 *
 * @author Cheng-Ru Lin
 * @version 1.0
 */
public class Rule{
    private RuleSet ruleset;
    LitemsetNode allset, cause, consequence;

    Rule(RuleSet ruleset, LitemsetNode allset, LitemsetNode cause){
        this.ruleset = ruleset; 
        this.allset = allset; 
        this.cause = cause;
        this.consequence = ruleset.getLatticeNode(
                allset.getLitemset().subtract(cause.getLitemset()));
    }

    private static double chi(double a, double b){
        return b > 1E-5 ? (a - b) * (a - b) / b : 0.0;
    }

    /**
     * Gets the ruleset where this rule be generated.
     *
     * @return the rule set where this rule generated
     */
    public RuleSet getRuleSet(){
            return ruleset;
    }

    /**
     * Gets the cause set of this rule.
     *
     * @return the cause set of this rule
     */
    public Litemset getCause(){
        return cause.getLitemset();
    }
    
    /**
     * Gets all the items of this rule.
     *
     * @return the all the items of this rule
     */
    public Litemset getItems(){
        return allset.getLitemset();
    }

    /**
     * Gets the consequence set of this rule.
     *
     * @return the consequence set of this rule
     */
    public Litemset getConsequence(){
        return consequence.getLitemset();
    }

    /**
     * Gets the confidence of this rule. Confidence is the ratio of
     * tansactions which contain all the elements of cause set also
     * contain the elements in the consequence set. For example, the
     * confidence of the rule: {milk} --> {bread}, is the ratio of
     * tansaction buying the milk also buy the bread.
     *
     * @return the confidence of this rule
     */
    public double getConfidence(){
        int all_count = allset.getLitemset().count, 
                cause_count = cause.getLitemset().count; 
        return ((double)all_count)/ cause_count;
    }

    /**
     * Gets the support of this rule. The support of a rule is the
     * ratio of tansactions contains both the cause set and the
     * consequence set.
     *
     * @return the support of this rule
     */
    public double getSupport(){
        int all_count = allset.getLitemset().count,
                tranx_count = ruleset.getTransactionCount();        
        return ((double)all_count)/tranx_count;
    }

    /**
     * Gets the chi square value of the rule. Chi square value is
     * used to measure the independence between the cause set and
     * consequence set. If they are totaly independent, then the
     * value should be zero. In the other words, if the values is
     * large enough, we may say that the cause set and consequence
     * set are associated.
     *
     * @return the chi square value of this rule
     */
    public double getChiSquare(){
        double a = cause.getLitemset().count,
            b = consequence.getLitemset().count,
            ab = allset.getLitemset().count,
            all = ruleset.getTransactionCount(), x = a * b / all;
        return chi(ab, x) + chi(b - ab, b - x) + 
                chi(a - ab, a - x) + 
                chi(all - a - b + ab, all - a - b + x);
    }

    /**
     * Gets the interesting index of this rule. The interesting of a
     * is defined as probability of the occurrence of both cause set
     * and consequence set over the product of the probability of
     * occurrence of cause set and that of consequnce set. For example,
     * in the rule {milk} --> {bread}, if there are 5% transactions
     * contains milk and 7% tansactions contains bread, and 3%
     * transactions contains both milk and bread, then the
     * interesting index of this rule is 0.03/(0.07*0.05) = 8.57.
     *
     * @return the interesting index of this rule
     */
    public double getInteresting(){
        double a = cause.getLitemset().count,
            b = consequence.getLitemset().count,
            ab = allset.getLitemset().count,
            all = ruleset.getTransactionCount();
        return (ab*all)/(a*b);
    }


    public String toString(){        
        return ruleset.toString(cause.getLitemset()) + " --> " + 
                ruleset.toString(consequence.getLitemset()) 
                + getSupport() + "," + getConfidence();
    }

}
